using EastenCommunication.BasicFramework;
using EastenCommunication.Core;
using EastenCommunication.Core.IMessage;
using EastenCommunication.Core.Net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace EastenCommunication.Profinet.LSIS
{
	/// <summary>
	/// LSisServer
	/// </summary>
	public class LSisServer : NetworkDataServerBase
	{
		private SoftBuffer pBuffer;

		private SoftBuffer qBuffer;

		private SoftBuffer mBuffer;

		private SoftBuffer dBuffer;

		private const int DataPoolLength = 65536;

		private int station = 1;

		private SerialPort serialPort;

		/// <summary>
		/// set plc
		/// </summary>
		public string SetCpuType
		{
			get;
			set;
		}

		/// <summary>
		/// LSisServer  
		/// </summary>
		public LSisServer(string CpuType)
		{
			pBuffer = new SoftBuffer(65536);
			qBuffer = new SoftBuffer(65536);
			mBuffer = new SoftBuffer(65536);
			dBuffer = new SoftBuffer(65536);
			SetCpuType = CpuType;
			base.WordLength = 2;
			base.ByteTransform = new RegularByteTransform();
			serialPort = new SerialPort();
		}

		/// <inheritdoc cref="M:EastenCommunication.Profinet.LSIS.XGBFastEnet.Read(System.String,System.UInt16)" />
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<string> operateResult = XGBFastEnet.AnalysisAddress(address, IsReadWrite: true);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			int num = CheckAddress(operateResult.Content.Substring(3));
			switch (operateResult.Content[1])
			{
			case 'P':
				return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(pBuffer.GetBool(num, length = (ushort)(length * 8))));
			case 'Q':
				return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(qBuffer.GetBool(num, length = (ushort)(length * 8))));
			case 'I':
			case 'M':
			case 'U':
				return OperateResult.CreateSuccessResult(SoftBasic.BoolArrayToByte(mBuffer.GetBool(num, length = (ushort)(length * 8))));
			case 'D':
			case 'T':
				return OperateResult.CreateSuccessResult(dBuffer.GetBytes((num == 0) ? num : (num *= 2), length));
			default:
				return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
			}
		}

		/// <inheritdoc cref="M:EastenCommunication.Profinet.LSIS.XGBFastEnet.Write(System.String,System.Byte[])" />
		public override OperateResult Write(string address, byte[] value)
		{
			string setCpuType = SetCpuType;
			string a = setCpuType;
			OperateResult<string> operateResult = (a == "XGK") ? XGBFastEnet.AnalysisAddress(address, IsReadWrite: true) : ((!(a == "XGB")) ? XGBFastEnet.AnalysisAddress(address, IsReadWrite: true) : XGBFastEnet.AnalysisAddress(address, IsReadWrite: false));
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			int num = CheckAddress(operateResult.Content.Substring(3));
			switch (operateResult.Content[1])
			{
			case 'P':
				pBuffer.SetBool((value[0] == 1) ? true : false, num);
				return OperateResult.CreateSuccessResult();
			case 'Q':
				qBuffer.SetBool((value[0] == 1) ? true : false, num);
				return OperateResult.CreateSuccessResult();
			case 'I':
			case 'M':
			case 'U':
				mBuffer.SetBool((value[0] == 1) ? true : false, num);
				return OperateResult.CreateSuccessResult();
			case 'D':
			case 'T':
				dBuffer.SetBytes(value, (num == 0) ? num : (num *= 2));
				return OperateResult.CreateSuccessResult();
			default:
				return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
			}
		}

		/// <inheritdoc cref="M:EastenCommunication.Profinet.LSIS.XGBFastEnet.ReadByte(System.String)" />
		public OperateResult<byte> ReadByte(string address)
		{
			return ByteTransformHelper.GetResultFromArray(Read(address, 2));
		}

		/// <inheritdoc cref="M:EastenCommunication.Profinet.LSIS.XGBFastEnet.Write(System.String,System.Byte)" />
		public OperateResult Write(string address, byte value)
		{
			return Write(address, new byte[1]
			{
				value
			});
		}

		/// <inheritdoc />
		public override OperateResult<bool> ReadBool(string address)
		{
			OperateResult<string> operateResult = XGBFastEnet.AnalysisAddress(address, IsReadWrite: true);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool>(operateResult);
			}
			int destIndex = CheckAddress(operateResult.Content.Substring(3));
			switch (operateResult.Content[1])
			{
			case 'P':
				return OperateResult.CreateSuccessResult(pBuffer.GetBool(destIndex));
			case 'Q':
				return OperateResult.CreateSuccessResult(qBuffer.GetBool(destIndex));
			case 'I':
			case 'M':
			case 'U':
				return OperateResult.CreateSuccessResult(mBuffer.GetBool(destIndex));
			case 'D':
				return OperateResult.CreateSuccessResult(dBuffer.GetBool(destIndex));
			default:
				return new OperateResult<bool>(StringResources.Language.NotSupportedDataType);
			}
		}

		/// <inheritdoc />
		public override OperateResult Write(string address, bool value)
		{
			string setCpuType = SetCpuType;
			string a = setCpuType;
			OperateResult<string> operateResult = (a == "XGK") ? XGBFastEnet.AnalysisAddress(address, IsReadWrite: true) : ((!(a == "XGB")) ? XGBFastEnet.AnalysisAddress(address, IsReadWrite: true) : XGBFastEnet.AnalysisAddress(address, IsReadWrite: false));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			int destIndex = CheckAddress(operateResult.Content.Substring(3));
			switch (operateResult.Content[1])
			{
			case 'P':
				pBuffer.SetBool(value, destIndex);
				return OperateResult.CreateSuccessResult();
			case 'Q':
				qBuffer.SetBool(value, destIndex);
				return OperateResult.CreateSuccessResult();
			case 'I':
			case 'M':
			case 'U':
				mBuffer.SetBool(value, destIndex);
				return OperateResult.CreateSuccessResult();
			case 'D':
				dBuffer.SetBool(value, destIndex);
				return OperateResult.CreateSuccessResult();
			default:
				return new OperateResult(StringResources.Language.NotSupportedDataType);
			}
		}

		/// <inheritdoc />
		protected override void ThreadPoolLoginAfterClientCheck(Socket socket, IPEndPoint endPoint)
		{
			AppSession appSession = new AppSession();
			appSession.IpEndPoint = endPoint;
			appSession.WorkSocket = socket;
			try
			{
				socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, SocketAsyncCallBack, appSession);
				AddClient(appSession);
			}
			catch
			{
				socket.Close();
				base.LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
			}
		}

		private void SocketAsyncCallBack(IAsyncResult ar)
		{
			AppSession appSession = ar.AsyncState as AppSession;
			if (appSession == null)
			{
				return;
			}
			try
			{
				int num = appSession.WorkSocket.EndReceive(ar);
				OperateResult<byte[]> operateResult = ReceiveByMessage(appSession.WorkSocket, 5000, new LsisFastEnetMessage());
				if (!operateResult.IsSuccess)
				{
					RemoveClient(appSession);
					return;
				}
				base.LogNet?.WriteDebug(ToString(), "Tcp " + StringResources.Language.Receive + "：" + operateResult.Content.ToHexString(' '));
				byte[] content = operateResult.Content;
				byte[] array = null;
				if (content[20] == 84)
				{
					array = ReadByMessage(content);
					RaiseDataReceived(array);
					appSession.WorkSocket.Send(array);
					goto IL_0119;
				}
				if (content[20] == 88)
				{
					array = WriteByMessage(content);
					RaiseDataReceived(array);
					appSession.WorkSocket.Send(array);
					goto IL_0119;
				}
				RemoveClient(appSession);
				goto end_IL_0019;
				IL_0119:
				base.LogNet?.WriteDebug(ToString(), "Tcp " + StringResources.Language.Send + "：" + array.ToHexString(' '));
				RaiseDataSend(content);
				appSession.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, SocketAsyncCallBack, appSession);
				end_IL_0019:;
			}
			catch
			{
				RemoveClient(appSession);
			}
		}

		private byte[] ReadByMessage(byte[] packCommand)
		{
			List<byte> list = new List<byte>();
			list.AddRange(ReadByCommand(packCommand));
			return list.ToArray();
		}

		private byte[] ReadByCommand(byte[] command)
		{
			List<byte> list = new List<byte>();
			list.AddRange(command.SelectBegin(20));
			list[9] = 17;
			list[10] = 1;
			list[12] = 160;
			list[13] = 17;
			list[18] = 3;
			list.AddRange(new byte[10]
			{
				85,
				0,
				20,
				0,
				8,
				1,
				0,
				0,
				1,
				0
			});
			int num = command[28];
			ushort length = BitConverter.ToUInt16(command, 30 + num);
			string @string = Encoding.ASCII.GetString(command, 31, num - 1);
			byte[] content = Read(@string, length).Content;
			list.AddRange(BitConverter.GetBytes((ushort)content.Length));
			list.AddRange(content);
			list[16] = (byte)(list.Count - 20);
			return list.ToArray();
		}

		private byte[] WriteByMessage(byte[] packCommand)
		{
			List<byte> list = new List<byte>();
			list.AddRange(packCommand.SelectBegin(20));
			list[9] = 17;
			list[10] = 1;
			list[12] = 160;
			list[13] = 17;
			list[18] = 3;
			list.AddRange(new byte[10]
			{
				89,
				0,
				20,
				0,
				8,
				1,
				0,
				0,
				1,
				0
			});
			int num = packCommand[28];
			string @string = Encoding.ASCII.GetString(packCommand, 31, num - 1);
			int length = BitConverter.ToUInt16(packCommand, 30 + num);
			byte[] value = base.ByteTransform.TransByte(packCommand, 32 + num, length);
			Write(@string, value);
			list[16] = (byte)(list.Count - 20);
			return list.ToArray();
		}

		/// <inheritdoc />
		protected override void LoadFromBytes(byte[] content)
		{
			if (content.Length < 262144)
			{
				throw new Exception("File is not correct");
			}
			pBuffer.SetBytes(content, 0, 0, 65536);
			qBuffer.SetBytes(content, 65536, 0, 65536);
			mBuffer.SetBytes(content, 131072, 0, 65536);
			dBuffer.SetBytes(content, 196608, 0, 65536);
		}

		/// <inheritdoc />
		protected override byte[] SaveToBytes()
		{
			byte[] array = new byte[262144];
			Array.Copy(pBuffer.GetBytes(), 0, array, 0, 65536);
			Array.Copy(qBuffer.GetBytes(), 0, array, 65536, 65536);
			Array.Copy(mBuffer.GetBytes(), 0, array, 131072, 65536);
			Array.Copy(dBuffer.GetBytes(), 0, array, 196608, 65536);
			return array;
		}

		/// <summary>
		/// NumberStyles HexNumber
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		private static bool IsHex(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			bool result = false;
			for (int i = 0; i < value.Length; i++)
			{
				switch (value[i])
				{
				case 'A':
				case 'B':
				case 'C':
				case 'D':
				case 'E':
				case 'F':
				case 'a':
				case 'b':
				case 'c':
				case 'd':
				case 'e':
				case 'f':
					result = true;
					break;
				}
			}
			return result;
		}

		/// <summary>
		/// Check the intput string address
		/// </summary>
		/// <param name="address"></param>
		/// <returns></returns>
		public static int CheckAddress(string address)
		{
			int result = 0;
			if (IsHex(address))
			{
				if (int.TryParse(address, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int result2))
				{
					result = result2;
				}
			}
			else
			{
				result = int.Parse(address);
			}
			return result;
		}

		/// <summary>
		/// 使用默认的参数进行初始化串口，9600波特率，8位数据位，无奇偶校验，1位停止位
		/// </summary>
		/// <param name="com">串口信息</param>
		public void StartSerialPort(string com)
		{
			StartSerialPort(com, 9600);
		}

		/// <summary>
		/// 使用默认的参数进行初始化串口，8位数据位，无奇偶校验，1位停止位
		/// </summary>
		/// <param name="com">串口信息</param>
		/// <param name="baudRate">波特率</param>
		public void StartSerialPort(string com, int baudRate)
		{
			StartSerialPort(delegate(SerialPort sp)
			{
				sp.PortName = com;
				sp.BaudRate = baudRate;
				sp.DataBits = 8;
				sp.Parity = Parity.None;
				sp.StopBits = StopBits.One;
			});
		}

		/// <summary>
		/// 使用自定义的初始化方法初始化串口的参数
		/// </summary>
		/// <param name="inni">初始化信息的委托</param>
		public void StartSerialPort(Action<SerialPort> inni)
		{
			if (!serialPort.IsOpen)
			{
				inni?.Invoke(serialPort);
				serialPort.ReadBufferSize = 1024;
				serialPort.ReceivedBytesThreshold = 1;
				serialPort.Open();
				serialPort.DataReceived += SerialPort_DataReceived;
			}
		}

		/// <summary>
		/// 关闭串口
		/// </summary>
		public void CloseSerialPort()
		{
			if (serialPort.IsOpen)
			{
				serialPort.Close();
			}
		}

		/// <summary>
		/// 接收到串口数据的时候触发
		/// </summary>
		/// <param name="sender">串口对象</param>
		/// <param name="e">消息</param>
		private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
		{
			SerialPort serialPort = (SerialPort)sender;
			int num = 0;
			byte[] array = new byte[1024];
			byte[] array2 = null;
			while (true)
			{
				Thread.Sleep(20);
				int num2 = serialPort.Read(array, num, serialPort.BytesToRead);
				num += num2;
				if (num2 == 0)
				{
					break;
				}
				array2 = new byte[num];
				Array.Copy(array, 0, array2, 0, num2);
			}
			if (array2 != null)
			{
				byte[] array3 = SoftBasic.ArrayRemoveLast(array2, 2);
				byte[] array4 = null;
				if (array3[3] == 114)
				{
					array4 = ReadSerialByCommand(array3);
					RaiseDataReceived(array4);
					this.serialPort.Write(array4, 0, array4.Length);
				}
				else if (array3[3] == 119)
				{
					array4 = WriteSerialByMessage(array3);
					RaiseDataReceived(array4);
					this.serialPort.Write(array4, 0, array4.Length);
				}
				else
				{
					this.serialPort.Close();
				}
				if (base.IsStarted)
				{
					RaiseDataSend(array2);
				}
			}
		}

		private byte[] ReadSerialByCommand(byte[] command)
		{
			List<byte> list = new List<byte>();
			list.Add(6);
			list.AddRange(SoftBasic.BuildAsciiBytesFrom((byte)station));
			list.Add(114);
			list.Add(83);
			list.Add(66);
			list.AddRange(Encoding.ASCII.GetBytes("01"));
			int num = int.Parse(Encoding.ASCII.GetString(command, 6, 2));
			int num2 = Convert.ToInt32(Encoding.ASCII.GetString(command, 8 + num, 2), 16);
			string @string = Encoding.ASCII.GetString(command, 9, num - 1);
			byte[] content = Read(@string, (ushort)num2).Content;
			list.AddRange(SoftBasic.BuildAsciiBytesFrom((byte)content.Length));
			list.AddRange(SoftBasic.BytesToAsciiBytes(content));
			list.Add(3);
			int num3 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				num3 += list[i];
			}
			list.AddRange(SoftBasic.BuildAsciiBytesFrom((byte)num3));
			return list.ToArray();
		}

		private byte[] WriteSerialByMessage(byte[] packCommand)
		{
			List<byte> list = new List<byte>();
			string @string = Encoding.ASCII.GetString(packCommand, 3, 3);
			list.Add(6);
			list.AddRange(SoftBasic.BuildAsciiBytesFrom((byte)station));
			list.Add(119);
			list.Add(83);
			list.Add(66);
			list.Add(3);
			if (@string == "wSS")
			{
				string string2 = Encoding.ASCII.GetString(packCommand, 8, 2);
				string string3 = Encoding.ASCII.GetString(packCommand, 11, int.Parse(string2) - 1);
				string string4 = Encoding.ASCII.GetString(packCommand, 10 + int.Parse(string2), 2);
				Write(string3, new byte[1]
				{
					(byte)((string4 == "01") ? 1u : 0u)
				});
			}
			else
			{
				string string2 = Encoding.ASCII.GetString(packCommand, 6, 2);
				string string3 = Encoding.ASCII.GetString(packCommand, 9, int.Parse(string2) - 1);
				int num = int.Parse(Encoding.ASCII.GetString(packCommand, 8 + int.Parse(string2), 2));
				string string5 = Encoding.ASCII.GetString(packCommand, 8 + int.Parse(string2) + num, num * 2);
				byte[] value = SoftBasic.HexStringToBytes(string5);
				Write(string3, value);
			}
			return list.ToArray();
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"LSisServer[{base.Port}]";
		}
	}
}
